#include "preHeader.h"
#include "GateServerSession.h"
#include "GateServerSessionHandler.h"
#include "ClientPacketHandler.h"
#include "SocialServerSession.h"
#include "CenterSession.h"
#include "GateServerMgr.h"
#include "MapServerMgr.h"
#include "GameServer.h"
#include "Game/AccountMgr.h"

GateServerSession::GateServerSession(uint32 sn)
: Session("GateServerSession")
, m_sn(sn)
, m_isReady(false)
{
}

GateServerSession::~GateServerSession()
{
}

int GateServerSession::HandlePacket(INetPacket *pck)
{
	if (IsReady() || pck->GetOpcode() < FLAG_GATE2GAME_MSG_NEED_REGISTER_BEGIN) {
		return sGateServerSessionHandler.HandlePacket(this, *pck);
	} else {
		return SessionHandleUnhandle;
	}
}

void GateServerSession::OnManaged()
{
	sGateServerMgr.AddGateServer(this);
	Session::OnManaged();
}

void GateServerSession::OnShutdownSession()
{
	sGateServerMgr.RemoveGateServer(this);
	WLOG("Close GateServerSession [sn:%u].", m_sn);
	Session::OnShutdownSession();
}

int GateServerSession::HandleClientPacket(uint32 uid, INetPacket& pck) const
{
	auto opcode = pck.GetOpcode();
	auto pAccount = sAccountMgr.GetAccount(uid);
	if (pAccount == NULL) {
		WLOG("Handle client packet[%u] failed, account(%u) offline.", opcode, uid);
		return SessionHandleSuccess;
	}

	if (opcode > FLAG_MSG_NEED_LOGIN_CHARACTER_BEGIN && !pAccount->IsCharacterOnline()) {
		WLOG("Handle client packet[%u] failed, character of account %u offline.", opcode, uid);
		return SessionHandleSuccess;
	}

	TRY_BEGIN {

		int retCode = sClientPacketHandler.HandlePacket(pAccount, pck);
		switch (retCode) {
		case SessionHandleSuccess:
			break;
		case SessionHandleCapture:
			break;
		case SessionHandleUnhandle:
			WLOG("SessionHandleUnhandle Account(%u) Opcode[%u].", uid, opcode);
			break;
		case SessionHandleWarning:
			WLOG("Handle Account(%u) Opcode[%u] Warning!", uid, opcode);
			break;
		case SessionHandleError:
			WLOG("Handle Account(%u) Opcode[%u] Error!", uid, opcode);
			break;
		case SessionHandleKill:
		default:
			WLOG("Fatal error occurred when processing account(%u) Opcode[%u].", uid, opcode);
			sAccountMgr.KickAccount(uid, SessionKickNetPacketError);
			break;
		case SessionHandleForward:
			if (pAccount->IsCharacterOnline()) {
				sMapServerMgr.RouteToPlayer(pAccount->GetCharacter(), pck);
			}
			break;
		}
		return retCode != SessionHandleCapture ? SessionHandleSuccess : SessionHandleCapture;

	} TRY_END
	CATCH_BEGIN(const IException &e) {
		WLOG("Handle packet account(%u) opcode[%u] exception occurred.", uid, opcode);
		e.Print();
		sAccountMgr.KillAccount(uid);
	} CATCH_END
	CATCH_BEGIN(...) {
		WLOG("Handle packet account(%u) opcode[%u] unknown exception occurred.", uid, opcode);
		sAccountMgr.KillAccount(uid);
	} CATCH_END

	return SessionHandleSuccess;
}

int GateServerSessionHandler::HandleRegister(GateServerSession *pSession, INetPacket &pck)
{
	bool flagHandlers[GAME_OPCODE::CSMSG_COUNT];
	sClientPacketHandler.InitHandlerFlags(flagHandlers, ARRAY_SIZE(flagHandlers));

	NetPacket resp(SGG_REGISTER_RESP);
	resp << sCenterSession.GetServerId() << pSession->sn()
		<< sSocialServerSession.getSocialListenAddr()
		<< sSocialServerSession.getSocialListenPort();
	resp.Append(flagHandlers, sizeof(flagHandlers));
	sMapServerMgr.PackAllMapServerInfos(resp);
	pSession->PushSendPacket(resp);

	pSession->m_isReady = true;
	NLOG("GateServer Register Success As [sn:%u].", pSession->m_sn);

	return SessionHandleSuccess;
}

int GateServerSessionHandler::HandleTransClientPacket(GateServerSession *pSession, INetPacket &pck)
{
	uint32 uid;
	pck >> uid;
	return pSession->HandleClientPacket(uid, pck.UnpackPacket());
}

int GateServerSessionHandler::HandleAccountLoginSucc(GateServerSession *pSession, INetPacket &pck)
{
	uint32 logicGsID, sn, uid;
	pck >> logicGsID >> sn >> uid;
	sAccountMgr.AddAccount(pSession, logicGsID, uid, sn);
	NLOG("client`%u` account`%u` login successfully.", sn, uid);
	return SessionHandleSuccess;
}

int GateServerSessionHandler::HandleAccountLogout(GateServerSession *pSession, INetPacket &pck)
{
	uint32 uid;
	pck >> uid;
	sAccountMgr.KickAccount(uid, SessionKickNormal);
	NLOG("client account`%u` logout.");
	return SessionHandleSuccess;
}
